package com.person.yhzs.wxPayV3.service.impl;

import com.person.yhzs.util.JsonUtil;
import com.person.yhzs.wxPayV3.common.WechatConstants;
import com.person.yhzs.wxPayV3.service.WXPayV3Service;
import com.person.yhzs.wxPayV3.util.WXPayV3Util;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author luolin
 * @Description
 * @createTime 2022年07月04日 15:16:00
 */
@Service
public class WXPayV3ServiceImpl implements WXPayV3Service {

    @Resource
    private WechatConstants wechatConstants;

    @Override
    public Map<String, Object> payWXOrder(HttpServletRequest request, String openId) throws IOException {

        // 获取请求ip地址
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getRemoteAddr();
        }
        if(ip.indexOf(",") != -1){
            String[] ips = ip.split(",");
            ip = ips[0].trim();
        }

        String mch_key_v3 = wechatConstants.getMCH_KEY_V3();
        String appid = wechatConstants.getAPPID();
        String mchId = wechatConstants.getMCH_ID();
        String mchSerialNo = wechatConstants.getMCH_SERIAL_NO();
//        String filename = "G:\\BaiduNetdiskDownload\\1627801713_20220627_cert\\apiclient_key.pem";
        String filename = wechatConstants.getAPI_CLIENT_KEY_PEM();

        // 读取文件中的密钥
        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");

        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(content.getBytes("utf-8")));

        CloseableHttpClient httpClient;
        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),mch_key_v3.getBytes("utf-8"));

        // 初始化httpClient
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();

        // 请求参数
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");

        String out_trade_no = UUID.randomUUID().toString().replaceAll("-","");
        // 请求body参数
        String reqdata = "{"
                + "\"amount\": {"
                + "\"total\": 1,"
                + "\"currency\": \"CNY\""
                + "},"
                + "\"mchid\": \"" + mchId + "\","
                + "\"description\": \"Image形象店-深圳腾大-QQ公仔\","
                + "\"notify_url\": \"https://luolin.vip/api/wxPay/success\","
                + "\"payer\": {"
                + "\"openid\": \"" + openId + "\"" + "},"
                + "\"out_trade_no\": \""+out_trade_no+"\","
                + "\"goods_tag\": \"WXG\","
                + "\"appid\": \"" + appid + "\"" + "}";

        StringEntity entity = new StringEntity(reqdata,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        Map<String, Object> resp = new HashMap<String,Object>();
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                String s = EntityUtils.toString(response.getEntity());
                resp = JsonUtil.readMap(s);
                System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
            } else if (statusCode == 204) {
                System.out.println("success");
            } else {
                System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
            httpClient.close();
        }
        // 预支付订单id
        String prepayId = (String) resp.get("prepay_id");
        resp.put("prepay_id", prepayId);
        // appid
        resp.put("appId", appid);
        // 时间戳
        String timestamp = WXPayV3Util.getTimestamp();
        resp.put("timeStamp", timestamp);
        // 随机字符串
        String nonceStr = WXPayV3Util.CreateNoncestr();
        resp.put("nonceStr", nonceStr);
        // 订单详情扩展字符串
        String packageStr = "prepay_id=" + prepayId;
        resp.put("package", packageStr);
        // 签名
        String paySign = WXPayV3Util.doRequestSign(content, appid, timestamp, nonceStr, packageStr);
        resp.put("paySign", paySign);
        resp.put("signType", "RSA");
        return resp;
    }
}
